package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;


    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    /**
     * 保存声音
     *
     * @param userId      用户ID
     * @param trackInfoVo 声音VO信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(Long userId, TrackInfoVo trackInfoVo) {
        //1.保存声音信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        //1.1 将用户提交VO转为PO对象
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        //1.2 手动赋值其他属性
        trackInfo.setUserId(userId);
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
        if (StringUtils.isBlank(trackInfo.getCoverUrl())) {
            trackInfo.setCoverUrl(albumInfo.getCoverUrl());
        }
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        //1.3 调用腾讯点播平台获取音视频文件详情信息-得到时长、大小、类型
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        trackInfoMapper.insert(trackInfo);
        Long trackInfoId = trackInfo.getId();

        //2.更新专辑信息（声音数量）
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        albumInfoMapper.updateById(albumInfo);

        //3.新增声音统计信息
        this.saveTrackStat(trackInfoId, SystemConstant.TRACK_STAT_PLAY, 0);
        this.saveTrackStat(trackInfoId, SystemConstant.TRACK_STAT_PRAISE, 0);
        this.saveTrackStat(trackInfoId, SystemConstant.TRACK_STAT_COLLECT, 0);
        this.saveTrackStat(trackInfoId, SystemConstant.TRACK_STAT_COMMENT, 0);

        //4.开启音视频任务审核；更新声音表：审核任务ID-后续采用定时任务检查审核结果
        //4.1 启动审核任务得到任务ID
        String reviewTaskId = vodService.reviewMediaTask(trackInfo.getMediaFileId());

        //4.2 更新声音表：审核任务ID，状态（审核中）
        trackInfo.setReviewTaskId(reviewTaskId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEW_ING);
        trackInfoMapper.updateById(trackInfo);
    }


    @Autowired
    private TrackStatMapper trackStatMapper;

    /**
     * 保存声音统计信息
     *
     * @param id
     * @param statType
     * @param num
     */
    @Override
    public void saveTrackStat(Long id, String statType, int num) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(id);
        trackStat.setStatType(statType);
        trackStat.setStatNum(num);
        trackStatMapper.insert(trackStat);
    }

    /**
     * 条件分页查询声音列表
     *
     * @param pageInfo       分页对象
     * @param trackInfoQuery 查询条件对象
     * @return
     */
    @Override
    public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.getUserTrackPage(pageInfo, trackInfoQuery);
    }

    /**
     * 修改声音信息
     *
     * @param id
     * @param trackInfo
     * @return
     */
    @Override
    public void updateTrackInfo(TrackInfo trackInfo) {
        //1.判断音频文件是否变更
        //1.1 根据声音ID查询声音记录得到“旧”的音频文件标识
        TrackInfo oldTrackInfo = trackInfoMapper.selectById(trackInfo.getId());
        //1.2 判断文件是否被更新
        if (!trackInfo.getMediaFileId().equals(oldTrackInfo.getMediaFileId())) {
            //1.3 如果文件被更新，再次获取新音频文件信息更新：时长，大小，类型
            TrackMediaInfoVo mediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
            if (mediaInfoVo != null) {
                trackInfo.setMediaType(mediaInfoVo.getType());
                trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));
                trackInfo.setMediaSize(mediaInfoVo.getSize());
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);

                // 音频文件发生更新后，必须再次进行审核
                //4. 开启音视频任务审核；更新声音表：审核任务ID-后续采用定时任务检查审核结果
                //4.1 启动审核任务得到任务ID
                String reviewTaskId = vodService.reviewMediaTask(trackInfo.getMediaFileId());
                //4.2 更新声音表：审核任务ID，状态（审核中）

                //4.2 更新声音表：审核任务ID，状态（审核中）
                trackInfo.setReviewTaskId(reviewTaskId);
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEW_ING);
                trackInfoMapper.updateById(trackInfo);
            }
            //1.4 从点播平台删除旧的音频文件
            vodService.deleteMedia(oldTrackInfo.getMediaFileId());
        }
        //2.更新声音信息
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 删除声音
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //1.查询声音信息 得到被删除声音所属专辑ID及序号
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();
        //2.删除声音-逻辑删除
        trackInfoMapper.deleteById(id);

        //3.更新声音序号 更新条件：专辑ID，声音序号大于被删除声音序号
        trackInfoMapper.updateOrderNum(albumId, orderNum);

        //4.删除统计信息
        LambdaQueryWrapper<TrackStat> trackStatLambdaQueryWrapper = new LambdaQueryWrapper<>();
        trackStatLambdaQueryWrapper.eq(TrackStat::getTrackId, id);
        trackStatMapper.delete(trackStatLambdaQueryWrapper);

        //5.删除点播平台音频文件
        vodService.deleteMedia(trackInfo.getMediaFileId());

        //6.更新专辑声音数量
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
    }

    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 分页查询专辑声音列表-动态根据用户情况展示声音付费标识
     *
     * @param userId   用户ID
     * @param albumId  专辑ID
     * @param pageInfo 分页对象
     * @return
     */
    @Override
    public Page<AlbumTrackListVo> getAlbumTrackPage(Long userId, Long albumId, Page<AlbumTrackListVo> pageInfo) {
        //1.根据专辑ID查询声音列表-AlbumTrackListVo对象中付费标识 "isShowPaidMark" 默认为false
        pageInfo = trackInfoMapper.getAlbumTrackPage(pageInfo, albumId);

        //TODO 根据用户情况（是否登录，是否会员，是否购买）动态判断是否需要付费
        //2.根据专辑ID查询专辑信息-得到专辑付费类型、专辑免费实体集数
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo, "专辑{}为空", albumId);
        //付费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        Integer tracksForFree = albumInfo.getTracksForFree();

        //3.处理用户未登录情况
        if (userId == null) {
            //3.1 专辑付费类型为：VIP免费 或者 付费 将除免费试听声音外，将其他声音付费标识设置为true
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                pageInfo.getRecords()
                        .stream().filter(vo -> vo.getOrderNum() > tracksForFree)
                        .forEach(vo -> {
                            //不免费声音全部设置：true
                            vo.setIsShowPaidMark(true);
                        });
            }
        } else {
            //4.处理用户已登录情况
            //4.1 远程调用用户服务获取用户信息-得到VIP标识及会员过期时间
            Boolean isVIP = false;
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo, "用户不存在！");
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                //是VIP条件：标识=1 且 会员过期时间大于当前时间
                isVIP = true;
            }

            //4.2 判断是否需要进一步判断用户购买情况
            Boolean isNeedCheckBuyState = false;

            //4.2.1 如果用户为普通用户 专辑 付费类型：VIP免费 需要进一步判断购买情况
            if (!isVIP && SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
                isNeedCheckBuyState = true;
            }

            //4.2.2 所有用户 专辑 付费类型：付费 需要进一步判断购买情况
            if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
                isNeedCheckBuyState = true;
            }

            //4.3 需要进一步判断用户购买情况
            if (isNeedCheckBuyState) {
                //4.3.1 远程调用用户服务：根据专辑ID+用户ID+当前页声音ID列表（将免费试听声音ID去掉）
                //将本页中声音为免费试听ID排除掉
                List<Long> needCheckBuyStateTrackIds = pageInfo.getRecords().stream()
                        .filter(vo -> vo.getOrderNum() > tracksForFree) //去除掉免费
                        .map(AlbumTrackListVo::getTrackId) //获取声音ID
                        .collect(Collectors.toList());
                //获取本页中声音购买情况Map
                Map<Long, Integer> buyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();

                //4.3.2 根据声音ID对应购买情况设置付费标识：如果用户未购买将付费标识设置：true 反之不需处理
                //遍历当前页中声音列表（将免费试听去掉）判断购买情况Map如果购买结果为：0 将该声音付费标识设置true,反之（已购买）保持默认付费标识false即可
                pageInfo.getRecords().stream()
                        .filter(vo -> vo.getOrderNum() > tracksForFree) //去除掉免费
                        .forEach(vo -> {
                            if (buyStateMap.get(vo.getTrackId()).intValue() == 0) {
                                //说明当前用户未购买该声音
                                vo.setIsShowPaidMark(true);
                            }
                        });
            }
        }
        return pageInfo;
    }

    /**
     * 查询声音统计信息
     *
     * @param trackId 声音ID
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackInfoMapper.getTrackStatVo(trackId);
    }

    /**
     * 基于用户选择购买声音动态返回分集购买列表
     *
     * @param userId  用户ID
     * @param trackId 选择购买声音ID
     * @return [{name:"本集",price:1,trackCount:1},{name:"后10集",price:10,trackCount:10}...{name:"全集/45集",price:45,trackCount:45}] 待结算声音数量45
     */
    @Override
    public List<Map<String, Object>> getUserFenJiBuyList(Long userId, Long trackId) {
        //1.根据声音ID查询声音信息 得到所属专辑ID、声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();

        //2.远程调用用户服务获取已购声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();

        //3.根据查询条件：专辑ID（等值）+序号（大于等于）、声音ID（not in）得到待购买声音数量
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, albumId);
        queryWrapper.ge(TrackInfo::getOrderNum, orderNum);
        if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
            //说明该专辑下用户存在已购买声音ID
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        Long waitBuyTrackCount = trackInfoMapper.selectCount(queryWrapper);

        //4.根据待结算声音数量动态构建分集购买列表
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        BigDecimal price = albumInfo.getPrice();
        List<Map<String, Object>> list = new ArrayList<>();
        //4.1 构建本集购买对象
        Map<String, Object> currMap = new HashMap<>();
        currMap.put("name", "本集");
        currMap.put("trackCount", 1);
        currMap.put("price", price);
        list.add(currMap);
        //4.2 构建其他分集购买对象
        //4.2.1 如果待结算声音长度在 N*10 - (N+1)*10 区间   48个
        for (int i = 10; i <= 50; i += 10) {
            //如果长度大于i 则显示 后 i 集
            if (waitBuyTrackCount > i) {
                Map<String, Object> map = new HashMap<>();
                map.put("name", "后" + i + "集");
                map.put("trackCount", i);
                map.put("price", price.multiply(BigDecimal.valueOf(i)));
                list.add(map);
            } else {
                //全集 精确集数
                Map<String, Object> map = new HashMap<>();
                map.put("name", "全集/后" + waitBuyTrackCount + "集");
                map.put("trackCount", waitBuyTrackCount);
                map.put("price", price.multiply(BigDecimal.valueOf(waitBuyTrackCount)));
                list.add(map);
                break;
            }
        }
        return list;
    }

    /**
     * 基于用户选购声音ID作为基准按照购买数量返回待购声音列表
     *
     * @param userId     用户ID
     * @param trackId    选购声音ID
     * @param trackCount 限制数量
     * @return
     */
    @Override
    public List<TrackInfo> getWaitBuyTrackInfoList(Long userId, Long trackId, int trackCount) {
        //1.根据声音ID查询声音信息 得到专辑ID，声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();
        //2.远程调用用户服务 得到已购声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();
        //3.根据专辑ID+声音序号（大于等于）+已购声音ID（not in）限制返回个数:trackCount 声音序号升序
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        //3.1 查询指定专辑
        queryWrapper.eq(TrackInfo::getAlbumId, albumId);
        //3.2 大于等于选择基准声音序号
        queryWrapper.ge(TrackInfo::getOrderNum, orderNum);
        if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
            //3.2 排除已购声音ID
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        //3.3 限制查询列 订单服务需要得到专辑信息 故多查询专辑ID列
        queryWrapper.select(TrackInfo::getId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
        //3.4 按照序号升序排序
        queryWrapper.orderByAsc(TrackInfo::getOrderNum);
        //3.5 限制返回数量
        queryWrapper.last("limit "+trackCount);
        List<TrackInfo> waitBuyTrackInfoList = trackInfoMapper.selectList(queryWrapper);
        return waitBuyTrackInfoList;
    }

}
